package com.central.scheduler.worker.plugin;

import com.central.scheduler.spi.SchedulerPlugin;
import com.central.scheduler.spi.classloader.ThreadContextClassLoader;
import com.central.scheduler.spi.plugin.AbstractPluginManager;
import com.central.scheduler.spi.task.TaskChannel;
import com.central.scheduler.spi.task.TaskChannelFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

/**
 * @author Tindy
 * @date 2021/10/26
 * @describe
 */
public class TaskPluginManager extends AbstractPluginManager {
    private static final Logger logger = LoggerFactory.getLogger(TaskPluginManager.class);
    private final Map<String, TaskChannelFactory> taskChannelFactoryMap = new ConcurrentHashMap<>();
    private final Map<String, TaskChannel> taskChannelMap = new ConcurrentHashMap<>();

    private void addTaskChannelFactory(TaskChannelFactory taskChannelFactory) {
        requireNonNull(taskChannelFactory, "taskChannelFactory is null");

        if (taskChannelFactoryMap.putIfAbsent(taskChannelFactory.getName(), taskChannelFactory) != null) {
            throw new IllegalArgumentException(format("Task Plugin '%s' is already registered", taskChannelFactory.getName()));
        }

        try {
            loadTaskChannel(taskChannelFactory.getName());
        } catch (Exception e) {
            throw new IllegalArgumentException(format("Task Plugin '%s' is can not load .", taskChannelFactory.getName()));
        }
    }
    private void loadTaskChannel(String name) {
        requireNonNull(name, "name is null");

        TaskChannelFactory taskChannelFactory = taskChannelFactoryMap.get(name);
        checkState(taskChannelFactory != null, "Task Plugin {} is not registered", name);

        try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(taskChannelFactory.getClass().getClassLoader())) {
            TaskChannel taskChannel = taskChannelFactory.create();
            this.taskChannelMap.put(name, taskChannel);
        }

        logger.info("-- Loaded Task Plugin {} --", name);
    }
    @Override
    public void installPlugin(SchedulerPlugin schedulerPlugin) {
        for (TaskChannelFactory taskChannelFactory : schedulerPlugin.getTaskChannelFactorys()) {
            logger.info("Registering Task Plugin '{}'", taskChannelFactory.getName());
            this.addTaskChannelFactory(taskChannelFactory);
        }
    }
    public Map<String, TaskChannel> getTaskChannelMap() {
        return taskChannelMap;
    }
}